package com.voice;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Arrays;

import android.app.Activity;
import android.content.Intent;
import android.media.MediaPlayer;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.TextView;

import com.alarm.R;
import com.musicg.fingerprint.FingerprintSimilarity;
import com.musicg.math.rank.ArrayRankDouble;
import com.musicg.math.statistics.StandardDeviation;
import com.musicg.wave.Wave;
import com.musicg.wave.extension.Spectrogram;
import com.notification.NotificationSetting;

public class SetVoice extends Activity {
	String TAG = "SetVoice";
	NotificationSetting setting;
	Button btnDiscard;
	Button btnRecord, startPlaybackButton;

	File path = new File(Environment.getExternalStorageDirectory().getPath() + "/WakeMeUp/");
	String recordingPath = path + "/original.wav";
	boolean isRecording = false;
	boolean isPlaying = false;
	ExtAudioRecorder audioRecorder;

	@Override
	public void onCreate(Bundle bundle) {
		super.onCreate(bundle);
		setContentView(R.layout.record_voice);
		bundle = this.getIntent().getExtras();
		setting = (NotificationSetting) bundle.get("setting");

		btnRecord = (Button) findViewById(R.id.StartRecordingButton);
		startPlaybackButton = (Button) findViewById(R.id.StartPlaybackButton);
		btnDiscard = (Button) findViewById(R.id.voiceDiscard);
		btnRecord.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				if (isRecording)
					stopRecording();
				else
					record(false);
			}
		});
		startPlaybackButton.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
				play();
			}
		});
		btnDiscard.setEnabled(setting.existVoice());
		path.mkdirs();
	}

	public void play() {
		Log.i(TAG, "SetVoice.play()");
		// startPlaybackButton.setEnabled(false);
		MediaPlayer mp = new MediaPlayer();
		try {
			mp.setDataSource(recordingPath);
			mp.prepare();
		} catch (IllegalArgumentException e) {
			e.printStackTrace();
		} catch (SecurityException e) {
			e.printStackTrace();
		} catch (IllegalStateException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		mp.start();
	}

	public void record(boolean validate) {
		Log.i(TAG, "SetVoice.record()");
		isRecording = true;
		btnDiscard.setEnabled(false);
		startPlaybackButton.setEnabled(false);
		btnRecord.setText("Stop Recording: " + recordingPath);
		File originalFile = new File(path + "/original.wav");
		File recordingFile = new File(path + "/recording.wav");
		originalFile.renameTo(recordingFile);
		audioRecorder = ExtAudioRecorder.getInstanse(false);
		audioRecorder.setOutputFile(recordingPath);
		audioRecorder.prepare();
		audioRecorder.start();
		TrackStatus track = new TrackStatus();
		track.execute();
	}

	public void stopRecording() {
		Log.i(TAG, "SetVoice.stopRecording()");
		audioRecorder.stop();
		audioRecorder.release();
		btnRecord.setText("Start Recording");
		setting.setVoice(recordingPath);
		btnDiscard.setEnabled(true);
		startPlaybackButton.setEnabled(true);
		isRecording = false;
	}

	public void onCancel(View v) {
		setResult(Activity.RESULT_CANCELED);
		finish();
	}

	public void onDiscardClick(View v) {
		setting.setVoice("");
		setting.save();
		v.setEnabled(false);
		startPlaybackButton.setEnabled(false);
	}

	public void onVoiceDoneClick(View v) {
		if (!setting.existVoice())
			setting.setVoiceOn(false);
		setting.save();
		Intent returnSetting = new Intent();
		Bundle bundle = new Bundle();
		bundle.putSerializable("setting", setting);
		returnSetting.putExtras(bundle);
		setResult(Activity.RESULT_OK, returnSetting);
		finish();
	}

	private double[] convert(double[][] array2D) {
		double[] rtn = new double[array2D.length+1];
		int i = 0;
		for (double[] array : array2D){
			double sum=0;
			for (double d : array)
				sum += d;
			rtn[i]=sum/array.length;
			if (rtn[i++] > rtn[rtn.length - 1])
				rtn[rtn.length - 1] = i;
		}
		return rtn;
	}
	public void onValidateClick(View v) {
		Button btnValidate = (Button) findViewById(R.id.validate);
		Log.i(TAG, "SetVoice.onValidateClick: " + path + "/original.wav");
		Log.i(TAG, "SetVoice.onValidateClick: " + recordingPath);
		if (!isRecording){
			isRecording = true;
			btnValidate .setText("Stop Recording");
			audioRecorder = ExtAudioRecorder.getInstanse(false);
			audioRecorder.setOutputFile(path + "/recording.wav");
			audioRecorder.prepare();
			audioRecorder.start();
			return;
		}

		Log.i(TAG, "SetVoice.stopRecording()");
		audioRecorder.stop();
		audioRecorder.release(); 
		isRecording = false;
		
		Wave original = new Wave(path + "/original.wav");
		Wave current = new Wave(path + "/recording.wav");
		Spectrogram origSp = original.getSpectrogram(4000, 0);
		Spectrogram currSp = current.getSpectrogram(4000, 0);
		double d1[][] = origSp.getNormalizedSpectrogramData();
		double d2[][] = currSp.getNormalizedSpectrogramData();
		double[] originalSpec = convert(d2), currentSpec = convert(d1);

		double[] shiftedSpec = currentSpec, nonShiftedSpec = originalSpec;
		int origPeak = (int) originalSpec[originalSpec.length - 1], currPeak = (int) currentSpec[currentSpec.length - 1];
		int diff = Math.abs(origPeak - currPeak);
		if (origPeak > currPeak) {
			shiftedSpec = originalSpec;
			nonShiftedSpec = currentSpec;
		}
		Log.d(TAG, "Ori:" + origPeak + " Curr: " + currPeak);
		Log.d(TAG, "Length- Shift:" + shiftedSpec.length + " Non: " + nonShiftedSpec.length);
		shiftedSpec = Arrays.copyOfRange(shiftedSpec, diff, shiftedSpec.length - 2 + diff);

		TextView status = (TextView) findViewById(R.id.status);
		double similarity = VoiceControlActivity.matchProportion(originalSpec, currentSpec);
		double similarityShift = VoiceControlActivity.matchProportion(shiftedSpec, nonShiftedSpec);
		status.setText((similarity > 0.8 ? "Passed" : "Failed") + 
				"\nSimilarity: " + similarity + "\nShifting:   " + similarityShift);
		Log.d(TAG, similarity+"\n"+similarityShift);
		
		btnValidate.setText("Validate");
		
	}

	public class TrackStatus extends AsyncTask<Void, Integer, Void> {
		final int WAIT_Time = 1000, MAX_Time = 5 * WAIT_Time;
		int status = 0;

		@Override
		protected synchronized Void doInBackground(Void... params) {
			Log.d(TAG, "color: Background Process.");
			int time = 0;
			while (isRecording && time < MAX_Time) {
				try {
					wait(WAIT_Time);
					time += WAIT_Time;
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
			Log.d(TAG, "time: " + time);
			return null;
		}

		protected void onPostExecute(Void result) {
			if (isRecording)stopRecording();
		}
	}
}
